package socket.test1Base;

import com.alibaba.fastjson.JSON;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

/**
 * Created by majian8 on 2019/6/22.
 *
 * InetAddress 是定位一个主机的，，URL是定位一个资源的
 */
public class Test1InetAddress {



    /**
     * InetAddress ip地址的高层抽象
     */
    @Test
    public void test1(){
        try {
            //1,如果以前查过了，会缓存在本地dns,否则的话会连接网络查找
            InetAddress address1=InetAddress.getByName("www.jd.com");
            System.out.println(address1.getHostName());
            System.out.println(address1.getHostAddress());

            //2,还可以根据ip来查域名 如果没有主机名的话，会返回这个ip地址
            System.out.println("=========address2");
            InetAddress address2=InetAddress.getByName("123.1.25.36");
            System.out.println(address2.getHostName());

            //3, 获取本机的 InetAddress对象
            System.out.println("=========address3");
            InetAddress address3=InetAddress.getLocalHost();
            System.out.println(address3.getHostName());

            //4,也可以通过ip地址获取 inetAddress,不用与dns交互，可以为不存在或无法解析的主机创建地址
            System.out.println("=========address4");
            byte [] addr=new byte[]{(byte)123,(byte)231,(byte)21,(byte)32};
            InetAddress address4=InetAddress.getByAddress(addr);
            System.out.println(address4.getHostName());

            //5,也可以用 ip地址字符串，也是不差dns可以为不存在或无法解析的主机创建地址
            //只有当请求主机名时，比如 调用getHostName()方法时才会查dns
            System.out.println("=========address5");
            InetAddress address5=InetAddress.getByName("192.168.1.23");
            System.out.println(address5.getHostName());
            //getHostName方法在不知道主机名时才会连接dns,getCanonicalHostName在知道主机名时也会连接，会替换缓存
            System.out.println(address5.getCanonicalHostName());

            //6, 返回的ip地址可能是负数，需要+256转成正数
            System.out.println("=========address6666");
            InetAddress address6=InetAddress.getByName("www.jd.com");
            System.out.println(address6.getAddress());

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    /**
     * 如果一个域名对应多个主机，可以通过getAllByName 来获取，返回的是一个数组,
     * (一般这个返回的是 vip不是真正的服务器地址（服务器地址一般是内网ip）)
     */
    @Test
    public void test2(){
        try {
            System.out.println(JSON.toJSONString(InetAddress.getAllByName("www.baidu.com")));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void test3(){
        //系统属性，查找dns成功时，在系统中的缓存时间
        System.out.println(System.getProperty("networkaddress.cache.ttl"));
        //系统属性，查找dns不成功时，在系统中的缓存时间
        System.out.println(System.getProperty("networkaddress.cache.negative.ttl"));
    }

    /**
     * 测试主机是否可达
     */
    @Test
    public void test4(){
        try {
            InetAddress address=InetAddress.getByName("www.baidu.com");
            System.out.println(address.isReachable(5*1000));
            //一般通过 getAddress()方法返回的数组的长度来判断是ipv4 还是ipv6
            System.out.println(address.getAddress().length);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 要测试一个主机地址能否解析时，可以用下面的方法，
     * 第二个参数 -1表示 能否用dns解析 hostname,如果大于-1
     * 表示是否允许在指定端口建立连接
     */
    @Test
    public void test5(){
        SecurityManager manager=new SecurityManager();
        manager.checkConnect("192.168.1.1",80);
    }



    /**
     * NetworkInterface 表示一个物理硬件地址和虚拟地址
     */
    @Test
    public void test6(){
        try {
            //1,
            NetworkInterface networkInterface=NetworkInterface.getByName("eth0");
            System.out.println(networkInterface);
            //2,此方法表示与指定ip地址绑定的网络接口，
            System.out.println("===========22222222");
            InetAddress address=InetAddress.getByName("10.0.70.246");
            NetworkInterface netInterface=NetworkInterface.getByInetAddress(address);
            System.out.println(netInterface);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取所有的网络接口
     */
    @Test
    public void test9(){
        try {
            Enumeration<NetworkInterface> face=NetworkInterface.getNetworkInterfaces();
            while(face.hasMoreElements()){
                NetworkInterface inte=face.nextElement();
                System.out.println(inte);
                //getDisplayName 返回更友好的名字
                System.out.println("======= "+inte.getDisplayName());
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }


    /**
     * 一个网络接口可用绑定多个ip地址
     */
    @Test
    public void test10(){
        try {
            NetworkInterface networkInterface=NetworkInterface.getByName("eth0");
            Enumeration<InetAddress> aa=networkInterface.getInetAddresses();
            while(aa.hasMoreElements()){
                InetAddress address=aa.nextElement();
                System.out.println(address);
            }

        } catch (SocketException e) {
            e.printStackTrace();
        }
    }



    @Test
    public void test(){

    }




    /**
     * jdk7中 引入了 try with resource,
     * 不需要在finally块中手动关闭了，
     * 会自动关闭实现了 AutoCloseable的流
     */
    @Test
    public void test13434(){
        try(FileOutputStream os=new FileOutputStream(new File("d:/a.txt"))){
            os.flush();
        }catch (Exception e){

        }
    }


    /**
     * io的write 方法 参数是int类型，但实际上，只能写入0-255 也就是一个字节（无符号的一个字节），
     * 超过这个字节 高三位的字节将会被丢弃，只保留低位的字节（java int强制转 char也是这个规则）
     * reader 和writer 是0 -65535 （写出和读取超过这个范围的会怎样？）
     */
    @Test
    public void test244(){
        try(FileOutputStream os=new FileOutputStream(new File("d:/a.txt"))){
            //1，向这个文件中写入 M  （acii码是77）
            os.write(77);
            //2，也可以尝试写一个负数，在文本编辑器中用二进制打开，会发现 会转化成
            //256 的整数倍，减掉这个负数，也就是最终转化成一个正数
            os.write(-300);

            //3,同理我们在读的时候,比如读一个字节，返回结果是int类型，比如 10000010，最高位1 表示有符号的
            //所以我们要对这个字节做转换  b=(b>0?b:256+b)
            FileInputStream in=new FileInputStream(new File("d:/a.txt"));
            int b=in.read(new byte[1]);
            b=(b>0?b:256+b);

            os.flush();
        }catch (Exception e){

        }
    }

}
